#include "px_textureatlas.h"
#include "../utility/px_system.h"
#include "../utility/px_macros.h"
#include <assert.h>
#include <math.h>
#define max(a,b) (a)>(b)?(a):(b)
static void  _init_indices(PXTEXTUREATLAS * atlas);
#define offsetof(s,m)   (size_t)&(((s *)0)->m)
#define PI 3.141592653
PXBOOL init_withtexture(PXTEXTUREATLAS* atlas,PXTEXTURE2D * texture,PXUINT32 capacity)
{
	atlas->capacity = capacity;
	atlas->total_quads = 0;
	atlas->ptexture = texture;
	atlas->pquads = (PXV3F_C4B_T2F_Quad*)calloc( sizeof(PXV3F_C4B_T2F_Quad) * capacity, 1 );
	atlas->pIndices = (short *)calloc( sizeof(short) * capacity * 6, 1 );
	if( ! ( atlas->pquads && atlas->pIndices ) && atlas->capacity > 0) {
		//CCLOG("cocos2d: CCTextureAtlas: not enough memory");
		PX_SAFE_FREE(atlas->pquads);
		PX_SAFE_FREE(atlas->pIndices );
		PX_SAFE_FREE(texture);
		return PXFALSE;
	}
	_init_indices(atlas);
	return PXTURE;
}
PXBOOL init_withfile(PXTEXTUREATLAS* atlas,const char * fileName,PXUINT32 capacity)
{
	PXTEXTURE2D * texture = create_texture2d(fileName);
	return init_withtexture(atlas,texture,capacity);
}
PXBOOL init_withfile_png(PXTEXTUREATLAS* atlas,const char * fileName,PXUINT32 capacity)
{
	PXTEXTURE2D * texture = create_texture2d_png(fileName);
	return init_withtexture(atlas,texture,capacity);
}


void update_quad(PXTEXTUREATLAS* atlas,PXV3F_C4B_T2F_Quad *quad, unsigned int index)
{
	assert( index >= 0 && index < atlas->capacity);
	atlas->total_quads = max( index+1, atlas->total_quads);
	atlas->pquads[index] = *quad;	
}



void insert_quad(PXTEXTUREATLAS* atlas,PXV3F_C4B_T2F_Quad * quad,PXINT32 index)
{
	PXINT32 remaining;
	assert(index < atlas->capacity);
	atlas->total_quads++;
	remaining = atlas->total_quads -1 -index;

	if( remaining > 0) {
		// texture coordinates
		memmove( &atlas->pquads[index+1],&atlas->pquads[index], sizeof(atlas->pquads[0]) * remaining );		
	}
   atlas->pquads[index] = *quad;
}
static void  _init_indices(PXTEXTUREATLAS * atlas)
{
	unsigned int i;
	if (atlas->capacity == 0)
		return;

	for(i=0; i < atlas->capacity; i++)
	{
#if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP
		atlas->pIndices[i*6+0] = i*4+0;
		atlas->pIndices[i*6+1] = i*4+0;
		atlas->pIndices[i*6+2] = i*4+2;		
		atlas->pIndices[i*6+3] = i*4+1;
		atlas->pIndices[i*6+4] = i*4+3;
		atlas->pIndices[i*6+5] = i*4+3;
#else
		atlas->pIndices[i*6+0] = (GLushort)(i*4+0);
		atlas->pIndices[i*6+1] = (GLushort)(i*4+1);
		atlas->pIndices[i*6+2] = (GLushort)(i*4+2);

		atlas->pIndices[i*6+3] = (GLushort)(i*4+3);
		atlas->pIndices[i*6+4] = (GLushort)(i*4+2);
		atlas->pIndices[i*6+5] = (GLushort)(i*4+1);		
#endif	
	}
}
static _draw_numbleofquads(PXTEXTUREATLAS * atlas,PXUINT32 n,PXUINT32 start)
{
		unsigned int offset = (unsigned int)atlas->pquads;
		unsigned int diff = offsetof( PXV3F_C4B_T2F, vertices);	



	   glEnable(GL_TEXTURE_2D);
	   glBindTexture(GL_TEXTURE_2D, atlas->ptexture->m_textureId);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

	   glBegin(GL_QUADS);

	   //glNormal3f(0.0, 1.0f, 0.0f);
	   glTexCoord2f(atlas->pquads->bl.texCoords.u, atlas->pquads->bl.texCoords.v);
	   glVertex3f(atlas->pquads->bl.vertices.x, atlas->pquads->bl.vertices.y, 0.0f);

	   glTexCoord2f(atlas->pquads->br.texCoords.u, atlas->pquads->br.texCoords.v);
	   glVertex3f(atlas->pquads->br.vertices.x, atlas->pquads->br.vertices.y, 0.0f);

	   glTexCoord2f(atlas->pquads->tr.texCoords.u, atlas->pquads->tr.texCoords.v);
	   glVertex3f(atlas->pquads->tr.vertices.x, atlas->pquads->tr.vertices.y, 0.0f);

	   glTexCoord2f(atlas->pquads->tl.texCoords.u, atlas->pquads->tl.texCoords.v);
	   glVertex3f(atlas->pquads->tl.vertices.x, atlas->pquads->tl.vertices.y, 0.0f);

// 	   glTexCoord2f(0.0f,1.0f);
// 	   glVertex3f(0.0f, 1.0f,0.0f);
// 
// 	   glTexCoord2f(1.0f, 1.0f);
// 	   glVertex3f(1.0f, 1.0f, 0.0f);
// 
// 	   glTexCoord2f(1.0f,0.0f);
// 	   glVertex3f(1.0f,0.0f, 0.0f);

	   glEnd();

	   /*
#define kQuadSize sizeof(atlas->pquads[0].bl)

		glVertexPointer(3, GL_FLOAT, kQuadSize, (GLvoid*) (offset + diff) );

		// color
		diff = offsetof( PXV3F_C4B_T2F, colors);
		glColorPointer(4, GL_UNSIGNED_BYTE, kQuadSize, (GLvoid*)(offset + diff));

		// texture coords
		diff = offsetof( PXV3F_C4B_T2F, texCoords);
		glTexCoordPointer(2, GL_FLOAT, kQuadSize, (GLvoid*)(offset + diff));

#if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP
		glDrawElements(GL_TRIANGLE_STRIP, n*6, GL_UNSIGNED_SHORT, atlas->pIndices + start * 6);	
#else
		glDrawElements(GL_TRIANGLES, n*6, GL_UNSIGNED_SHORT, atlas->pIndices + start * 6);	
#endif
#*/
}
void draw_quads(PXTEXTUREATLAS * atlas)
{
	_draw_numbleofquads(atlas,atlas->total_quads,0);
}

void remove_allQuads(PXTEXTUREATLAS * atlas)
{
	atlas->total_quads = 0;
}

static void _try_toRotateMlg(PXV3F_C4B_T2F_Quad* quad, RotateParam* _rp)
{
	float src_x ,angle,center_x,center_y,src_y;
	float width  = (float)	SCREEN_WIDTH /2;
	float height =  (float) SCREEN_HEIGHT/2;
	float test;
	float test2;
// 	if ( NULL == _rp || fabs(_rp->angle) < 1e-6 )
// 		return;
	angle = _rp->angle*PI/180, center_x = _rp->center_point.x, center_y = _rp->center_point.y;

	src_x = quad->tl.vertices.x - center_x, src_y = quad->tl.vertices.y - center_y;
	quad->tl.vertices.x =(src_x*cos(angle) + src_y*sin(angle) + center_x)/width;
	quad->tl.vertices.y = (src_y*cos(angle) - src_x*sin(angle) + center_y)/height;

	src_x = quad->tr.vertices.x - center_x, src_y = quad->tr.vertices.y - center_y;
	quad->tr.vertices.x = (src_x*cos(angle) + src_y*sin(angle) + center_x)/width;
	quad->tr.vertices.y = (src_y*cos(angle) - src_x*sin(angle) + center_y)/height;

	src_x = quad->bl.vertices.x - center_x, src_y = quad->bl.vertices.y - center_y;
	quad->bl.vertices.x = (src_x*cos(angle) + src_y*sin(angle) + center_x)/width;
	quad->bl.vertices.y = (src_y*cos(angle) - src_x*sin(angle) + center_y)/height;

	src_x = quad->br.vertices.x - center_x, src_y = quad->br.vertices.y - center_y;
	quad->br.vertices.x = (src_x*cos(angle) + src_y*sin(angle) + center_x)/width;
	quad->br.vertices.y = (src_y*cos(angle) - src_x*sin(angle) + center_y)/height;

}

void setQuad( PXTEXTUREATLAS * atlas,float x,float y,float w, float h,float * texCoor,unsigned int n,RotateParam * rp)
{
	PXV3F_C4B_T2F_Quad * quad ;
	PXSIZE scene_size= {SCREEN_WIDTH,SCREEN_HEIGHT};
	float width;
	float height;
	atlas->total_quads = max( n+1,atlas->total_quads);
	quad = &atlas->pquads[n];
    width  = (float)	SCREEN_WIDTH /2;
	height =  (float) SCREEN_HEIGHT/2;
	if(rp == NULL) 
	{
		quad->bl.vertices =vertex3((float) x/width,(float) y/height,0.0f);
		quad->br.vertices =vertex3((float) (x+w)/width,(float) y/height,0.0f);
		quad->tr.vertices =vertex3((float) (x+w)/width,(float) (y+h)/height,0.0f);
		quad->tl.vertices =vertex3((float) x/width,(float) (y+h)/height,0.0f);
	}
	else
	{
		quad->bl.vertices =vertex3((float) x,(float) y,0.0f);
		quad->br.vertices =vertex3((float) (x+w),(float) y,0.0f);
		quad->tr.vertices =vertex3((float) (x+w),(float) (y+h),0.0f);
		quad->tl.vertices =vertex3((float) x,(float) (y+h),0.0f);
	}
	
	
	quad->tl.texCoords = tex2((float) texCoor[0]/atlas->ptexture->width, (float) texCoor[1]/atlas->ptexture->height);			
	quad->tr.texCoords = tex2((float) (texCoor[0]+w)/atlas->ptexture->width, (float) texCoor[1]/atlas->ptexture->height);			
	quad->br.texCoords = tex2((float) (texCoor[0]+w)/atlas->ptexture->width, (float) (texCoor[1]+h)/atlas->ptexture->height);
	quad->bl.texCoords = tex2((float) (texCoor[0])/atlas->ptexture->width, (float) (texCoor[1]+h)/atlas->ptexture->height);
	if(rp == NULL) 
		return;
	_try_toRotateMlg(quad,rp);
	
}




